const fs = require('fs');
const path = require('path');

// 统一配置：确保采样率和声道数在全局保持一致
const AUDIO_CONFIG = {
  sampleRate: 44100,    // 标准采样率
  numChannels: 1,       // 单声道
  bitsPerSample: 16     // 16位深度
};

function convertToWav(buffer, sampleRate = AUDIO_CONFIG.sampleRate) {
  console.log('开始WAV格式转换, 缓冲区长度:', buffer.length);
  if (!(buffer instanceof Float32Array)) {
    throw new Error(`无效的音频缓冲区类型: ${typeof buffer}, 预期Float32Array`);
  }
  if (buffer.length === 0) {
    throw new Error('音频缓冲区为空, 无法转换为WAV');
  }

  // 转换为16位PCM
  const pcmData = new Int16Array(buffer.length);
  for (let i = 0; i < buffer.length; i++) {
    const value = Math.max(-1, Math.min(1, buffer[i]));
    pcmData[i] = value < 0 ? value * 0x8000 : value * 0x7FFF;
  }

  // WAV文件头配置
  const numChannels = AUDIO_CONFIG.numChannels;
  const bytesPerSample = AUDIO_CONFIG.bitsPerSample / 8;
  const blockAlign = numChannels * bytesPerSample;
  const byteRate = sampleRate * blockAlign;
  const dataSize = pcmData.length * bytesPerSample;
  const totalSize = 44 + dataSize;

  // 创建WAV文件头
  const wavBuffer = Buffer.alloc(totalSize);
  wavBuffer.write('RIFF', 0);
  wavBuffer.writeUInt32LE(totalSize - 8, 4);
  wavBuffer.write('WAVE', 8);
  wavBuffer.write('fmt ', 12);
  wavBuffer.writeUInt32LE(16, 16); // 子块大小
  wavBuffer.writeUInt16LE(1, 20);  // PCM格式
  wavBuffer.writeUInt16LE(numChannels, 22);
  wavBuffer.writeUInt32LE(sampleRate, 24);
  wavBuffer.writeUInt32LE(byteRate, 28);
  wavBuffer.writeUInt16LE(blockAlign, 32);
  wavBuffer.writeUInt16LE(AUDIO_CONFIG.bitsPerSample, 34); // 位深度
  wavBuffer.write('data', 36);
  wavBuffer.writeUInt32LE(dataSize, 40);

  // 写入PCM数据
  for (let i = 0; i < pcmData.length; i++) {
    wavBuffer.writeInt16LE(pcmData[i], 44 + i * bytesPerSample);
  }

  console.log(`WAV转换完成: 时长=${(buffer.length / sampleRate).toFixed(2)}秒, 大小=${wavBuffer.length}字节`);
  return wavBuffer;
}

async function generatePianoAudio(frequency, outputDir = 'audio/piano', duration = 5, saveToFile = true) {
  console.log('进入generatePianoAudio函数, 目标时长:', duration, '秒');
  const sampleRate = AUDIO_CONFIG.sampleRate;
  const amplitude = 0.8;

  console.log(`开始生成频率为${frequency}Hz的钢琴音频...`);
  // 关键修复：获取原始样本（不再是提前转换的WAV）
  const rawSamples = await generatePianoTone(frequency, duration, sampleRate);
  console.log(`原始样本生成完成: 样本数=${rawSamples.length}, 理论时长=${(rawSamples.length / sampleRate).toFixed(2)}秒`);

  // 创建输出目录
  try {
    if (!fs.existsSync(outputDir)) {
      fs.mkdirSync(outputDir, { recursive: true });
      console.log(`成功创建输出目录: ${outputDir}`);
    }
  } catch (mkdirError) {
    console.error(`创建目录失败: ${mkdirError.message}`);
    throw new Error(`创建目录失败: ${mkdirError.message}`);
  }

  // 生成文件名
  const timestamp = new Date().toISOString()
    .replace(/:/g, '-')
    .replace(/\./g, '-');
  const fileName = `piano_${frequency}hz_${timestamp}.wav`;
  const filePath = path.join(outputDir, fileName);

  // 应用振幅并转换为WAV（仅处理一次）
  const adjustedSamples = new Float32Array(rawSamples.length);
  for (let i = 0; i < rawSamples.length; i++) {
    adjustedSamples[i] = rawSamples[i] * amplitude;
  }

  // 转换为WAV格式（单一入口）
  const wavData = convertToWav(adjustedSamples, sampleRate);

  // 写入文件或返回数据
  try {
    if (saveToFile) {
      fs.writeFileSync(filePath, wavData);
      console.log(`钢琴音频文件已保存: ${filePath}`);
      return fileName;
    } else {
      return wavData;
    }
  } catch (writeError) {
    console.error('写入音频文件失败:', writeError);
    throw new Error(`无法写入音频文件: ${writeError.message}`);
  }
}

function generatePianoTone(frequency, duration = 5, sampleRate = AUDIO_CONFIG.sampleRate) {
  // 验证参数
  if (typeof frequency !== 'number' || isNaN(frequency) || frequency <= 0) {
    throw new Error(`无效的频率参数: ${frequency} (必须是大于0的数字)`);
  }
  if (typeof duration !== 'number' || duration <= 0) {
    throw new Error(`无效的时长参数: ${duration} (必须是大于0的数字)`);
  }

  console.log(`生成钢琴音: 频率=${frequency}Hz, 时长=${duration}秒, 采样率=${sampleRate}`);
  // 关键修复：计算正确的样本数（采样率 × 时长）
  const totalSamples = Math.floor(sampleRate * duration);
  const buffer = new Float32Array(totalSamples);
  
  // 钢琴泛音列
  const harmonics = [
    { freq: 1, amp: 1.0 }, { freq: 2, amp: 0.65 }, { freq: 3, amp: 0.35 },
    { freq: 4, amp: 0.20 }, { freq: 5, amp: 0.12 }, { freq: 6, amp: 0.08 },
    { freq: 7, amp: 0.05 }, { freq: 8, amp: 0.04 }, { freq: 9, amp: 0.03 },
    { freq: 10, amp: 0.02 }
  ];

  const CHUNK_SIZE = 1000;
  let processed = 0;

  return new Promise((resolve, reject) => {
    // 处理样本分块
    function processChunk() {
      try {
        const start = processed;
        const end = Math.min(start + CHUNK_SIZE, totalSamples);

        for (let i = start; i < end; i++) {
          const time = i / sampleRate; // 时间（秒）
          let sample = 0;

          // 叠加泛音
          for (let j = 0; j < harmonics.length; j++) {
            const h = harmonics[j];
            const angle = 2 * Math.PI * h.freq * frequency * time;
            sample += Math.sin(angle) * h.amp;
          }

          // 应用包络（确保包络与时长匹配）
          const envelope = getPianoEnvelope(time, duration);
          buffer[i] = sample * envelope;
        }

        processed = end;
        if (processed < totalSamples) {
          setImmediate(processChunk);
        } else {
          console.log('样本生成完成，开始归一化');
          normalizeBuffer();
        }
      } catch (error) {
        console.error('样本处理错误:', error);
        reject(error);
      }
    }

    // 归一化处理
    function normalizeBuffer() {
      let maxAmplitude = 0;
      let maxAmpProcessed = 0;

      // 查找最大振幅
      function findMaxAmplitude() {
        try {
          const start = maxAmpProcessed;
          const end = Math.min(start + CHUNK_SIZE, buffer.length);

          for (let i = start; i < end; i++) {
            const absValue = Math.abs(buffer[i]);
            if (absValue > maxAmplitude) {
              maxAmplitude = absValue;
            }
          }

          maxAmpProcessed = end;
          if (maxAmpProcessed < buffer.length) {
            setImmediate(findMaxAmplitude);
          } else {
            // 避免除以0
            if (maxAmplitude < 1e-9) maxAmplitude = 1e-9;
            applyNormalization();
          }
        } catch (error) {
          console.error('计算最大振幅错误:', error);
          reject(error);
        }
      }

      // 应用归一化
      function applyNormalization() {
        let normProcessed = 0;

        function normalizeChunk() {
          try {
            const start = normProcessed;
            const end = Math.min(start + CHUNK_SIZE, buffer.length);

            for (let i = start; i < end; i++) {
              buffer[i] = buffer[i] / maxAmplitude; // 归一化到[-1, 1]
            }

            normProcessed = end;
            if (normProcessed < buffer.length) {
              setImmediate(normalizeChunk);
            } else {
              console.log('归一化完成，返回原始样本');
              // 关键修复：返回原始样本（而非提前转换的WAV）
              resolve(buffer);
            }
          } catch (error) {
            console.error('归一化错误:', error);
            reject(error);
          }
        }

        normalizeChunk();
      }

      findMaxAmplitude();
    }

    processChunk();
  });
}

// 修复包络函数：确保在短时长长也能正常工作
function getPianoEnvelope(time, duration) {
  const attack = 0.02;       //  Attack (20ms)
  const decay = 0.3;         //  Decay (300ms)
  const sustainLevel = 0.2;  //  Sustain level (20% of peak)
  const release = Math.min(2.0, duration * 0.5); //  Release (最长2秒，或时长的一半)

  // 确保release不超过总时长
  const sustainEnd = duration - release;
  if (sustainEnd < 0) {
    // 当时长小于release时，直接进入衰减阶段
    return 1 - (time / duration);
  }

  if (time < attack) {
    return time / attack; // Attack phase
  } else if (time < attack + decay) {
    const t = time - attack;
    return 1 - (1 - sustainLevel) * (t / decay); // Decay phase
  } else if (time < sustainEnd) {
    return sustainLevel; // Sustain phase
  } else {
    const t = time - sustainEnd;
    return sustainLevel * (1 - t / release); // Release phase
  }
}

module.exports = { generatePianoAudio, generatePianoTone }
